package org.springframework.beans.factory.config;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.anno.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/12/12
 */
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements PropertyValueBeanDefinitionPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    //处理@Autowired 属性
    @Override
    public void postProcessBeanDefinitionPropertyValue(BeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        Field[] fields = beanType.getDeclaredFields();
        List<PropertyValue> pvs = beanDefinition.getPropertyValues();
        if(null==pvs||pvs.isEmpty()){
            pvs = new ArrayList<>();
        }
        for (Field field:fields) {
            if(field.isAnnotationPresent(Autowired.class)){
                Autowired auto = field.getAnnotation(Autowired.class);
                if(auto.required()){
                    pvs.add(new PropertyValue(field.getName(),new BeanReference(field.getName())));
                }
            }
        }
        beanDefinition.setPropertyValues(pvs);
    }


    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
        //所有的构造器
        Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();

        //@Autowired(false)的构造器
        List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);

        //@Autowired(true)的构造器
        Constructor<?> requiredConstructor = null;

        //默认无参构造器
        Constructor<?> defaultConstructor = null;

        //最终返回的构造器
        Constructor<?>[] candidateConstructors = null;


        for (Constructor<?> candidate : rawCandidates) {
            Autowired auto = candidate.getAnnotation(Autowired.class);
            if(auto!=null){
                //取出Autowired的属性值required
                boolean required = auto.required();
                //如果是true
                if (required) {
                    //@Autowired(true)的构造器只能有一个 ，如果多个直接报错
                    if (requiredConstructor != null) {
                        throw new RuntimeException("find more than one required(true) constructor when determine "+beanName+" constructor");
                    }
                    //给requiredConstructor赋值
                    requiredConstructor = candidate;
                }
                //添加到false构造器集合
                candidates.add(candidate);
            }//给默认构造器赋值
            else if (candidate.getParameterCount() == 0) {
                defaultConstructor = candidate;
            }
        }

        // true的构造器
        if(requiredConstructor!=null){
            candidateConstructors = new Constructor<?>[] {requiredConstructor};
        }
        //false的构造器
        else if (!candidates.isEmpty()) {
            //只有Autowried(false)会出现candidates不空，而requiredConstructor为空的现象
            if (requiredConstructor == null) {
                //添加默认的
                if (defaultConstructor != null) {
                    candidates.add(defaultConstructor);
                }
            }
            candidateConstructors = candidates.toArray(new Constructor<?>[0]);
        }
        //只有一个构造器（有参），直接返回这个就行了
        else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
            candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
        }
        else {
            candidateConstructors = new Constructor<?>[0];
        }

        return (candidateConstructors.length > 0 ? candidateConstructors : null);
    }
}
